// 框架的boot文件，主要负责生成globalProperties中的FoundationFrameworkDef结构
import axios from 'axios'

import {App, ref} from 'vue'
import {Router} from 'vue-router'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import relativeTime from 'dayjs/plugin/relativeTime'
import _ from 'lodash'

import {
  AppConfigDef,
  GlobalCfgDef,
  NjtPackInfoDef,
  PackageInfoDef,
  UserAuth,
  UserRoleRightInfo,
} from './defs/comm'

// Helpers
import ui from './helper/ui'
import lst from './helper/dropdownlist'
import misc from './helper/misc'
import fmt from './helper/fmt'
import nw from './helper/network'
import regex from './helper/regex'
import valFuncs from './helper/validate-functions'
import validators from './helper/validators'
import {getAxiosErrMsg, getAxiosErrCode, getAxiosErrIcon, getFieldErrStr} from './helper/errorhandler'
import {getLabelAltTextsData, prepareAltLabelTextsFunc} from './helper/label-alt-texts'

// Components
import components from './components'

const adminAccount = 'admin'

// 在boot时候调用这个方法, meta是新的参数，vite构建器提供
export default async (app: App, router: Router, globalCfg: GlobalCfgDef, env: ImportMetaEnv) => {
  const envVite = env

  // 获取网站静态资源URL，参数url: 如'appconfig.json'，前面不需要加'/'，生成这样的地址：/foundation-sample/appconfig.json
  const getSiteUrl = (url: string) => {
    return envVite.BASE_URL + url
  }

  // region 从localStorage还原ua,rr,unreadMsgNum信息
  let ua = null
  let rr = null
  let unreadMsgNum = ref(0)
  const uaJson = localStorage.getItem('ua')
  if (uaJson) {
    ua = ref(JSON.parse(uaJson) as UserAuth)
  }
  const rrJson = localStorage.getItem('rr')
  if (rrJson) {
    rr = ref(JSON.parse(rrJson) as UserRoleRightInfo)
  }
  const unreadMsgNumJson = localStorage.getItem('unreadMsgNum')
  if (unreadMsgNumJson) {
    unreadMsgNum = ref(parseInt(unreadMsgNumJson))
  }
  // endregion

  // region AXIOS配置
  const feAxios = axios.create()

  let appCfg: AppConfigDef
  if (globalCfg.manuallySetAppconfigJson) {
    //先给个空白的
    appCfg = {
      apiBaseUrl: '',
      websiteBaseUrl: '',
    }
  } else {
    const result = await feAxios.get<AppConfigDef>(getSiteUrl('appconfig.json?v=' + Date.now()))
    appCfg = result.data
  }

  const fxAxios = axios.create({
    baseURL: appCfg.apiBaseUrl,
    withCredentials: true,
  })
  fxAxios.interceptors.request.use(function (config) {
    const ua = $f.ua
    if (ua) {
      config.headers!['username'] = encodeURI(ua.value.userName)
      config.headers!['auth-token'] = ua.value.appToken
    }
    if ($f.globalCfg.supportLanguageSwitch) {
      config.headers!['accept-Language'] = window.localStorage.getItem('lang')??navigator.language
    }
    return config
  }, function (error) {
    return Promise.reject(error)
  })

  fxAxios.interceptors.response.use(function (response) {
    return response
  }, function (error) {
    if (error.response) {
      if (error.response.status === 401) {
        if (!_.startsWith(router.currentRoute.value.path.toLowerCase(), '/comm/auth/login')) {
          void router.push({path: '/comm/auth/login', query: {reurl: router.currentRoute.value.fullPath}})
        }
      }
      else if (error.response.status === 502){
        $f.errorState.value = 3 //502错误
      }
    }
    return Promise.reject(error)
  })

  // endregion

  // region ROUTER配置
  if (globalCfg.manuallyConfigVueRouter) {
    // router此时似乎不需要做什么
  } else {
    router.beforeEach((to, from, next) => {
      $f.toSetErrorState = 0
      const ua = $f.ua
      if (to.meta.needLogin !== false && !ua) {
        next({
          path: '/comm/auth/login',
          query: {reurl: to.path},
        })
      } else {
        if (to.meta.needRight && !$f.hasRight(to.meta.needRight as string)) {
          $f.toSetErrorState = 2
        }
        next()
      }
    })
    router.afterEach(() => {
      $f.errorState.value = $f.toSetErrorState
    })
  }
  //endregion

  // region 框架相关方法定义
  const hasRight = function (rightKey: string): boolean {
    if (!$f.ua || !$f.rr || !_.isString($f.ua.value.userName) || !_.isArray($f.rr.value.rightKeys)) {
      return false
    }
    if ($f.ua.value.userName.toLowerCase() === adminAccount) {
      return true
    }
    return $f.rr.value.rightKeys.includes(rightKey)
  }

  const hasRightsOr = function (...rights: string[]): boolean {
    if (!$f.ua || !$f.rr || !_.isString($f.ua.value.userName) || !_.isArray($f.rr.value.rightKeys)) {
      return false
    }
    if ($f.ua.value.userName.toLowerCase() === adminAccount) {
      return true
    }
    let flag = false
    _.map(rights, (o) => {
      if ($f.rr?.value.rightKeys.includes(o)) {
        flag = true
      }
    })
    return flag
  }

  const hasModifyRightsOr = function (...rights: string[]): boolean {
    return !$f.isAppReadonly.value && hasRightsOr(...rights)
  }
  const hasRightsAnd = function (...rights: string[]): boolean {
    if (!$f.ua || !$f.rr || !_.isString($f.ua.value.userName) || !_.isArray($f.rr.value.rightKeys)) {
      return false
    }
    if ($f.ua.value.userName.toLowerCase() === adminAccount) {
      return true
    }
    let flag = true
    _.map(rights, (o) => {
      if (!$f.rr?.value.rightKeys.includes(o)) {
        flag =  false
      }
    })
    return flag
  }
  const hasModifyRightsAnd = function (...rights: string[]): boolean {
    return !$f.isAppReadonly.value && hasRightsAnd(...rights)
  }
  const hasModifyRight = function (rightKey: string): boolean {
    return !$f.isAppReadonly.value && hasRight(rightKey)
  }

  // 默认先弄个空的
  const emptyNjtPackInfo: NjtPackInfoDef = {
    miiReg: '',
    copyrightProprietor: '',
  }

  // 默认先弄个空的
  const emptyPackageInfo: PackageInfoDef = {
    njtconfig: emptyNjtPackInfo,
    productName: '',
    version: '',
    copyrightYear: '',
  }
  // endregion

  // 文本替换初始化
  getLabelAltTextsData(fxAxios)

  // region 一些初始化动作
  // 配置使用处理相对时间的插件
  dayjs.extend(relativeTime)
  // 配置使用中文语言包
  dayjs.locale('zh-cn')

  // 各个插件
  app.use(components)

  // endregion

  window.$f = {
    axios: fxAxios,
    feAxios: feAxios,
    appCfg,
    packageInfo: emptyPackageInfo, //先放一个空的后面会更新为真实的
    rr,
    ua,
    unreadMsgNum,
    errorState: ref(0),
    toSetErrorState: 0,
    isAppReadonly: ref(false),
    hasRight,
    hasModifyRight,
    hasRightsOr,
    hasModifyRightsOr,
    hasRightsAnd,
    hasModifyRightsAnd,
    getAxiosErrMsg,
    getAxiosErrCode,
    getAxiosErrIcon,
    getFieldErrStr,
    globalCfg,
    router,
    ui,
    lst,
    misc,
    fmt,
    nw,
    regex,
    valFuncs,
    validators,
    getSiteUrl,
    prepareAltLabelTextsFunc,
  }
}
